﻿//load required components from google visualization API
google.load('visualization', '1', { 'packages': ['corechart', 'gauge', 'table'] });

//define object to perform ELBMonitor functions
function ASDashboard(asGroupsRefreshUrl, elbRequestDataUrl, capacityDataRefreshUrl, allCpuUsageRefreshUrl, instanceHealthRefreshUrl, instanceCpuUsageRefreshUrl, refreshLengthMilliseconds, asGroupName, loadBalancerName, elbGraphContainerId, capacityGraphContainerId, allCpuUsageGraphContainerId, instanceHealthContainerId, instanceCpuUsageGraphContainerId) {
    //set configurable options on this instance
    this.asGroupsRefreshUrl = asGroupsRefreshUrl;
    this.hasSetupGroupsMenuKo = false;
    this.elbDataRefreshUrl = elbRequestDataUrl;
    this.capacityDataRefreshUrl = capacityDataRefreshUrl;
    this.allCpuUsageRefreshUrl = allCpuUsageRefreshUrl;
    this.instanceHealthRefreshUrl = instanceHealthRefreshUrl;
    this.instanceCpuUsageRefreshUrl = instanceCpuUsageRefreshUrl;
    this.instanceHealthStatusContainerId = instanceHealthContainerId;

    this.ASGroupName = asGroupName;
    this.LoadBalancerName = loadBalancerName;

    this.ShowInstanceCpuHistory = false;

    this.RefreshLengthMilliseconds = refreshLengthMilliseconds;
    
    //get a self reference to be referred to in delegate function
    var instance = this;
    
    $("#showHide").bind("click", function () { instance.ToggleHistory(); });

    //perofrm display work after page-load
    google.setOnLoadCallback(function () {

        //initialise visualizations (and keep a reference so that we can update them rather than create new ones each time.
        //browsers will crash when recreating google visualizations with a lot of data many times
        instance.requestChart = new google.visualization.AreaChart(document.getElementById(elbGraphContainerId));
        instance.capacityChart = new google.visualization.AreaChart(document.getElementById(capacityGraphContainerId));
        instance.allCpuUsageChart = new google.visualization.AreaChart(document.getElementById(allCpuUsageGraphContainerId));
        instance.instanceStatusChart = new google.visualization.Table(document.getElementById(instanceHealthContainerId));

        // healthTable - column sort
        instance.healthTableSortColumn = 0;
        instance.healthTableSortColumnASC = true;
        google.visualization.events.addListener(instance.instanceStatusChart, 'sort', function (e) {
            // Hook into the google table sorting event so we can persist the sorting across table refreshes
            instance.healthTableSortColumn = e.column;
            instance.healthTableSortColumnASC = e.ascending;
        });

        // cpu usage element
        instance.instanceCpuUsageElement = $("#" + instanceCpuUsageGraphContainerId);

        // Container to hold visualisation charts
        instance.instanceCpuUsageCharts = {};

        // array to contain instanceIDs of all instances currently in the load balancer
        instance.currentInstances = new Array();

        //set interval to refresh data via ajax. remember timeout-id so wait can be cancelled.
        instance.RefreshAutoScaleGroupsDataAsync();
        instance.RefreshRequestDataAsync();
        instance.RefreshCapacityDataAsync();
        instance.RefreshAllCpuUsageDataAsync();
        instance.RefreshInstanceStatusDataAsync();
        instance.RefreshInstanceCpuUsageDataAsync();


        //on resize, re-layout
        $(window).resize(instance.ResizeClientElements);

    });

    // Maintain focus state
    instance.InFocus = true;
    $(window).focusout(function () { instance.InFocus = false; });
    $(window).focusin(function () { instance.InFocus = true; });

}

ASDashboard.prototype.StartTimerRefreshAutoScaleGroupsData = function () {
    var self = this;
    self.RefreshAutoScaleGroupsDataTimeoutId = window.setTimeout(function () { self.RefreshAutoScaleGroupsDataAsync(); }, self.RefreshLengthMilliseconds);
};
ASDashboard.prototype.StartTimerRefreshRequestData = function () {
    var self = this;
    self.RefreshRequestDataTimeoutId = window.setTimeout(function () { self.RefreshRequestDataAsync(); }, self.RefreshLengthMilliseconds);
};

ASDashboard.prototype.StartTimerRefreshCapacityData = function () {
    var self = this;
    self.RefreshCapacityDataTimeoutId = window.setTimeout(function () { self.RefreshCapacityDataAsync(); }, self.RefreshLengthMilliseconds);
};

ASDashboard.prototype.StartTimerRefreshAllCpuUsageData = function () {
    var self = this;
    self.RefreshAllCpuUsageDataTimeoutId = window.setTimeout(function () { self.RefreshAllCpuUsageDataAsync(); }, self.RefreshLengthMilliseconds);
};

ASDashboard.prototype.StartTimerRefreshInstanceStatusData = function () {
    var self = this;
    self.RefreshInstanceStatusDataTimeoutId = window.setTimeout(function () { self.RefreshInstanceStatusDataAsync(); }, self.RefreshLengthMilliseconds);
};

ASDashboard.prototype.StartTimerRefreshInstanceCpuUsageData = function () {
    var self = this;
    self.RefreshInstanceCpuUsageDataTimeoutId = window.setTimeout(function () { self.RefreshInstanceCpuUsageDataAsync(); }, self.RefreshLengthMilliseconds);
};

ASDashboard.prototype.ToggleHistory = function () {
    var self = this;
    self.ShowInstanceCpuHistory = self.ShowInstanceCpuHistory == true ? false : true;

    if (self.ShowInstanceCpuHistory) {
        $("#InstanceCpuChart").css("height", "auto");
        $("#showHide").text('hide');
    } else {
        $("#InstanceCpuChart").css("height", "0");
        $("#showHide").text('show');
    }
};

ASDashboard.prototype.RefreshAutoScaleGroupsDataAsync = function () {
    window.clearTimeout(this.RefreshAutoScaleGroupsDataTimeoutId);

    var instance = this;
	if (instance.InFocus == true) {
		$.ajax({
			url: this.asGroupsRefreshUrl,
			type: 'GET',
			dataType: 'json',
			error: function(error) {
				console.log('error loading auto-scale groups: ' + error.toString());
			},
			success: function(result) {
				if (instance.hasSetupGroupsMenuKo !== true) {
					//first time, setup viewmodel, apply bindings
					instance.hasSetupGroupsMenuKo = true;
					instance.MenuViewModel = ko.mapping.fromJS(result);
					ko.applyBindings(instance.MenuViewModel, document.getElementById("AutoScaleGroups"));
				} else {
					ko.mapping.fromJS(result, instance.MenuViewModel);
				}
			}
		});
	}
	//set interval to refresh data via ajax. remember timeout-id so wait can be cancelled.
    instance.StartTimerRefreshAutoScaleGroupsData();
};

ASDashboard.prototype.RefreshRequestDataAsync = function () {
    //since this function could be called manually, clear any timeout waiting to call this method, since we don't want 
    //to be interrupted and we will reset the timeout anyway when the data is retreived and set.
    window.clearTimeout(this.RefreshRequestDataTimeoutId);

    //self-reference for callbacks
    var instance = this;

    if (instance.InFocus == true) {
		$.ajax({
			url: this.elbDataRefreshUrl,
			type: 'POST',
			data: ({ loadBalancerName: this.LoadBalancerName }),
			dataType: 'json',
			error: function(error) {
				//TODO: show that there was a brief interruption, but that we are resuming
				console.log('error loading request data:' + error.toString());
			},
			success: function(result) {

				var dataItems = result.Data;
				//initialise data table
				var data = new google.visualization.DataTable();
				data.addColumn('string', 'Date');
				data.addColumn('number', '2wks');
				data.addColumn('number', '1wk');
				data.addColumn('number', 'ydy');
				data.addColumn('number', 'tdy');

				//add rows for each data item we have
				data.addRows(dataItems.length);

				//parse data, setting value for each cell as we find them
				for (var j in dataItems) {
					data.setValue(parseInt(j), 0, dataItems[j].Date);
					for (var k in dataItems[j].Data) {
						data.setValue(parseInt(j), parseInt(k) + 1, dataItems[j].Data[k] == 0 ? null : dataItems[j].Data[k]);
					}
				}

				//draw new data to chart
				instance.requestChart.draw(data, instance.ELBChartOptions);

			}
		});
	}
	
	//set interval to refresh data via ajax. remember timeout-id so wait can be cancelled.
    instance.StartTimerRefreshRequestData();
};

ASDashboard.prototype.RefreshCapacityDataAsync = function () {
    //since this function could be called manually, clear any timeout waiting to call this method, since we don't want 
    //to be interrupted and we will reset the timeout anyway when the data is retreived and set.
    window.clearTimeout(this.RefreshCapacityDataTimeoutId);

    //self-reference for callbacks
    var instance = this;

    if (instance.InFocus == true) {
		//get capacity history data
		$.ajax({
			url: this.capacityDataRefreshUrl,
			type: 'POST',
			data: ({ autoScaleGroupName: this.ASGroupName }),
			dataType: 'json',
			error: function(error) {
				//TODO: show that there was a brief interruption, but that we are resuming
				console.log('error loading capacity data:' + error.toString());
			},
			success: function(result) {
				var dataItems = result.Data;
				//initialise data table
				var data = new google.visualization.DataTable();
				data.addColumn('string', 'Date');
				data.addColumn('number', 'Yesterday');
				data.addColumn('number', 'Today');

				//add rows for each data item we have
				data.addRows(dataItems.length);

				//parse data, setting value for each cell as we find them
				for (var j in dataItems) {
					data.setValue(parseInt(j), 0, dataItems[j].Date);
					for (var k in dataItems[j].Data) {
						data.setValue(parseInt(j), parseInt(k) + 1, dataItems[j].Data[k] == 0 ? null : dataItems[j].Data[k]);
					}
				}

				//draw new data to chart
				instance.capacityChart.draw(data, instance.ELBChartOptions);
			}
		});
	}

	//set interval to refresh data via ajax. remember timeout-id so wait can be cancelled.
	instance.StartTimerRefreshCapacityData();
};

ASDashboard.prototype.RefreshAllCpuUsageDataAsync = function () {
    //since this function could be called manually, clear any timeout waiting to call this method, since we don't want 
    //to be interrupted and we will reset the timeout anyway when the data is retreived and set.
    window.clearTimeout(this.RefreshAllCpuUsageDataTimeoutId);

    //self-reference for callbacks
    var instance = this;

    if (instance.InFocus == true) {
		//get capacity history data
		$.ajax({
			url: this.allCpuUsageRefreshUrl,
			type: 'POST',
			data: ({ autoScaleGroupName: this.ASGroupName }),
			dataType: 'json',
			error: function(error) {
				//TODO: show that there was a brief interruption, but that we are resuming
				console.log('error loading all CPU usage data:' + error.toString());
			},
			success: function(result) {
				//current cpu
				$('#CurrentCpu').html(' (Currently reads ' + result.CurrentValue + '%)');

				var dataItems = result.Data;
				//initialise data table
				var data = new google.visualization.DataTable();
				data.addColumn('string', 'Date');
				data.addColumn('number', 'Yesterday');
				data.addColumn('number', 'Today');

				//add rows for each data item we have
				data.addRows(dataItems.length);

				//parse data, setting value for each cell as we find them
				for (var j in dataItems) {
					data.setValue(parseInt(j), 0, dataItems[j].Date);
					for (var k in dataItems[j].Data) {
						data.setValue(parseInt(j), parseInt(k) + 1, dataItems[j].Data[k] == 0 ? null : dataItems[j].Data[k]);
					}
				}

				//draw new data to chart
				instance.allCpuUsageChart.draw(data, instance.ELBChartOptions);
			}
		});
	}
	
	//set interval to refresh data via ajax. remember timeout-id so wait can be cancelled.
    instance.StartTimerRefreshAllCpuUsageData();
};

ASDashboard.prototype.RefreshInstanceStatusDataAsync = function () {
    //since this function could be called manually, clear any timeout waiting to call this method, since we don't want 
    //to be interrupted and we will reset the timeout anyway when the data is retreived and set.
    window.clearTimeout(this.RefreshInstanceStatusDataTimeoutId);

    //self-reference for callbacks
    var instance = this;

    if (instance.InFocus == true) {
		//get capacity history data
		$.ajax({
			url: this.instanceHealthRefreshUrl,
			type: 'POST',
			data: ({ loadBalancerName: this.LoadBalancerName }),
			dataType: 'json',
			error: function(error) {
				//TODO: show that there was a brief interruption, but that we are resuming
				console.log('error loading instance status data:' + error.toString());
			},
			success: function(result) {
				var dataItems = result;
				//initialise data table
				var data = new google.visualization.DataTable();
				data.addColumn('string', 'InstanceId');
				data.addColumn('string', 'CPU Usage');
				data.addColumn('string', 'State');
				data.addColumn('string', 'Reason');
				data.addColumn('string', 'Up Time');
				data.addColumn('string', 'Public DNS');
				data.addColumn('string', 'Zone');

				//add rows for each data item we have
				data.addRows(dataItems.length);

				// local array to keep track of current instances
				instance.currentInstances.splice(0);

				//parse data, setting value for each cell as we find them
				for (var j in dataItems) {
					data.setValue(parseInt(j), 0, dataItems[j].Id);
					data.setValue(parseInt(j), 1, dataItems[j].CpuNow + '%');
					data.setValue(parseInt(j), 2, dataItems[j].State);
					data.setValue(parseInt(j), 3, dataItems[j].Reason);
					data.setValue(parseInt(j), 4, dataItems[j].UpTime);
					data.setValue(parseInt(j), 5, dataItems[j].PublicDnsName);
					data.setValue(parseInt(j), 6, dataItems[j].Placement);

					// keep track of what instances we currenty have
					instance.currentInstances.push(dataItems[j].RawId);
				}

				//draw new data to chart
				instance.instanceStatusChart.draw(data, {
					sortColumn: instance.healthTableSortColumn,
					sortAscending: instance.healthTableSortColumnASC,
					allowHtml: true
				});
			}
		});
	}
	
	//set interval to refresh data via ajax. remember timeout-id so wait can be cancelled.
    instance.StartTimerRefreshInstanceStatusData();
};

ASDashboard.prototype.RefreshInstanceCpuUsageDataAsync = function () {

    //self-reference for callbacks
    var instance = this;

    //since this function could be called manually, clear any timeout waiting to call this method, since we don't want 
    //to be interrupted and we will reset the timeout anyway when the data is retreived and set.
    window.clearTimeout(this.RefreshInstanceCpuUsageDataTimeoutId);

    // only make the call if we have some instances
    if (instance.currentInstances.length && instance.ShowInstanceCpuHistory && instance.InFocus) {
        //get capacity history data
        $.ajax({
            url: this.instanceCpuUsageRefreshUrl,
            type: 'POST',
            data: (JSON.stringify(instance.currentInstances)),
            contentType: "application/json; charset=utf-8",
            dataType: 'json',
            error: function (error) {
                //TODO: show that there was a brief interruption, but that we are resuming
                console.log('error loading instance CPU data:' + error.toString());
            },
            success: function (result) {
                // the result is an array of instance CPU usage historys
                var instancesCpuHistory = result;

                $("#loadingProgress").remove();

                // get all instance graph DIVs currently rendered
                var $existingGraphs = $("#InstanceCpuChart > div");

                for (var inst in instancesCpuHistory) {
                    var currentInstance = instancesCpuHistory[inst];

                    var instanceId = currentInstance.InstanceId;
                    var friendlyName = currentInstance.FriendlyName;
                    var currentValue = currentInstance.CurrentValue; // CPU Value
                    var dataItems = currentInstance.Data; // Data Points

                    //initialise data table
                    var data = new google.visualization.DataTable();
                    data.addColumn('string', 'Date');
                    data.addColumn('number', 'Yesterday');
                    data.addColumn('number', 'Today');

                    //add rows for each data item we have
                    data.addRows(dataItems.length);

                    //parse data, setting value for each cell as we find them
                    for (var j in dataItems) {
                        data.setValue(parseInt(j), 0, dataItems[j].Date);
                        for (var k in dataItems[j].Data) {
                            data.setValue(parseInt(j), parseInt(k) + 1, dataItems[j].Data[k] == 0 ? null : dataItems[j].Data[k]);
                        }
                    }

                    // If the chart DIV hasn't been created, need to create it
                    if (instance.instanceCpuUsageCharts[instanceId] == null) {
                        // create a new DIV to hold chart
                        instance.instanceCpuUsageElement
                        .append($("<div/>").attr("id", instanceId)
                            .append($("<h3/>").attr("id", "header" + instanceId))
                            .append($("<div/>").attr("id", "chart" + instanceId))
                            .css("width", "100%"));

                        instance.instanceCpuUsageCharts[instanceId] = new google.visualization.AreaChart($("#chart" + instanceId)[0]);
                    }

                    $('#header' + instanceId).text('CPU Usage history for ' + instanceId + ' (' + friendlyName + ')' + ' - Currently reads ' + currentValue + '%:');

                    // a wee bit of customisation for instance charts
                    var instanceCpuOptions = $.extend({}, instance.ELBChartOptions);
                    instanceCpuOptions.vAxis = { textStyle: { color: 'white' }, maxValue: 100 };

                    // draw the new data
                    instance.instanceCpuUsageCharts[instanceId].draw(data, instanceCpuOptions);

                    // update the list of graphs so it doesn't include this graph
                    $existingGraphs = $existingGraphs.not("#" + instanceId);
				}
                instance.StartTimerRefreshInstanceCpuUsageData();

                // remove everything left over from the DOM as those instances no longer exist 
                $existingGraphs.remove();
            }
        });
    }
	
	//set interval to refresh data via ajax. remember timeout-id so wait can be cancelled.
    instance.StartTimerRefreshInstanceCpuUsageData();
};

//options for elb traffic day-comparison graph
ASDashboard.prototype.ELBChartOptions = {

    curveType: "function",
    isStacked: false,
    legend: "none",
    axisTitlesPosition: 'none',
    backgroundColor: 'black',
    chartArea: { left: 50, top: 0, width: "100%", height: "75%" },
    hAxis: { textStyle: { color: 'white' } },
    vAxis: { textStyle: { color: 'white' } },
    colors: ['green', 'yellow', 'red', 'blue']
};